using PhraseCorrector.Common;
using PhraseCorrector.SimplePinyin;
using PhraseCorrector.SpellCorrect;
using PhraseCorrector.SpellLook;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace PhraseCorrector.DirectTanslate
{
    /**
     * 中英术语翻译类
     * 1. 术语翻译
     * 2. 术语拼写检查
     * 3. 术语拼写修正
     * 4. 术语拼写推荐
     * 5. 术语拼写推荐+翻译
     */
    public class EnglishTraslator : IEnumerable<string>
    {

        #region 英译中直译词树变量

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 英文多单词树
        /// </summary>
        /// <remarks>
        /// 术语翻译库，用于存储英中对照字典。
        /// 中文单字之间不允许存在空格，可存在'_'
        /// </summary>
        public static Dictionary<string, string> EClibrary { set; get; } = new Dictionary<string, string>();

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 最大容错单词个数
        /// </summary>
        private static int MaxLength { set; get; } = 3;

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 纠错词库对象（初始化时使用）
        /// </summary>
        private readonly English_Chinese_Dictionary ECDics = null;


        #endregion

        #region 西文词库的创建与更新
        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 初始化ChinesePhraselibrary类的实例。
        /// </summary>
        public EnglishTraslator()
        {
            if (EClibrary.Count == 0)
                 throw new Exception("请先载入西文词库！");
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 初始化ChinesePhraselibrary类的实例。
        /// </summary>
        /// <param name="eCDics">纠错词库对象</param>
        public EnglishTraslator(English_Chinese_Dictionary eCDics) {
            ECDics = eCDics;
            EnglishLoading();
            // 默认最大容错单词个数是短语长度的一半
            MaxLength =  (int)(EnglishSpell.SpellHandle.MaxLength * 0.5);
        }

        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 载入常用词库
        /// </summary>
        public void EnglishLoading() {
            TryLoadSpecialedlibrary();
            if (BasePath.DicsModel == LibraryType.All || BasePath.DicsModel == LibraryType.Phrase) TryLoadlibrary();
            new EnglishSpell();
        }

        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取表示是否存在的库文件的布尔值属性。
        /// </summary>
        /// <value>如果库文件存在则返回true，否则返回false。</value>
        private bool SpecializedIsExis
        {
            get
            {
                FileInfo fileInfo = new FileInfo(BasePath.SpecializedDictionaryPath);
                return fileInfo.Exists;
            }
        }

        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 尝试加载特化库。
        /// </summary>
        /// <remarks>
        /// 如果特化库存在，则从特化库文件路径加载。
        /// </remarks>
        public void TryLoadSpecialedlibrary()
        {
            if (SpecializedIsExis)
                LoadFromFile(BasePath.SpecializedDictionaryPath);
        }

        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 尝试加载英汉双语库。
        /// </summary>
        /// <remarks>
        /// 如果应按字典存在，则从该字典加载。
        /// </remarks>
        public void TryLoadlibrary()
        {
            foreach (var line in ECDics.English_Chinese_library)
                if (BasePath.DicsModel != LibraryType.Phrase || line.Key.Split(' ').Length > 1)
                    Add(line.Key, line.Value);
        }

        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 逐行加载文件内容，并处理每一行。
        /// </summary>
        /// <param name="fInfo">要加载的文件信息。</param>
        private void LoadFromFile(string path)
        {
            // 使用StreamReader读取文件内容
            using StreamReader sr1 = new StreamReader(path);
            // 循环读取文件的每一行，直到文件结束
            while (sr1.Peek() != -1)
                ReadAndInsert(sr1.ReadLine());
        }

        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 读取一行文件内容，并尝试插入到术语字典中。
        /// </summary>
        /// <param name="line">一行文件内容。</param>
        private void ReadAndInsert(string line)
        {
            // 如果行内容不为空，则处理并尝试添加到字典中
            if (!string.IsNullOrEmpty(line))
                TryAdd(DicsUtilities.FormatECDicsLine(line.Split(' ')));
        }

        // ///////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 尝试将解析后的键值对添加到术语字典中。
        /// </summary>
        /// <param name="keyValue">解析后的键值对数组。</param>
        private void TryAdd(string[] keyValue)
        {
            // 如果解析出了键和值，则尝试添加到术语字典中
            if (keyValue.Length == 2 && Utilities.IsChineseBegin(keyValue[1]))
                Add(keyValue[0], keyValue[1]);
        }

        #endregion

        #region 生成词树

        // ///////////////////////////////////////////////////////////////////////////////      
        /// <summary>
        /// 添加术语到词树
        /// </summary>
        /// <param name="sentance">术语句子</param>
        /// <param name="chinese">对应的中文解释</param>
        public void Add(string sentance, string chinese)
        {
            // 将句子和对应的中文解释添加到词树中
            EClibrary[sentance] = chinese;

            // 对句子进行分割并进一步添加
            //Add(sentance.Split(' '));
        }

        // ///////////////////////////////////////////////////////////////////////////////       
        /// <summary>
        /// 递归添加术语
        /// </summary>
        /// <param name="list">术语列表</param>
        private void Add(string[] list)
        {
            // 遍历术语列表，生成所有可能的子术语并添加
            for (int i = 1; i < list.Length; i++)
                Add(string.Join(' ', list[..i]));
        }

        // ///////////////////////////////////////////////////////////////////////////////      
        /// <summary>
        /// 向词树中添加片段
        /// </summary>
        /// <param name="fragment">片段</param>
        private void Add(string fragment)
        {
            // 如果片段不存在于词树中，则将其添加，初始解释为空
            if (!EClibrary.TryGetValue(fragment, out _))
                EClibrary.TryAdd(fragment, "");
        }

        #endregion

        #region 字典树速查

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 在内容中查找所有匹配的术语
        /// </summary>
        /// <param name="content">待查找的内容</param>
        /// <returns>匹配的术语列表，包括中文解释、结束位置和匹配度</returns>
        public static List<PhraseResult> TreeSearch(string content)
        {
            var instance = new EnglishTraslator();
            // 剔除符号后进行字典树快速查找
            return instance.FindAllResult(content, new FastTree(EClibrary).TransformCustomizedWords(instance.RegexSuggestArray(content)));
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 将中文标点符号后的空格规范化
        /// </summary>
        /// <param name="content">输入的字符串内容</param>
        /// <returns>规范化后的字符串数组</returns>
        public string[] RegexSuggestArray(string content)
        {
            // 使用正则表达式替换中文标点符号后的空格
            return Utilities.ReplaceBdfh(content, " ").Split(' ');
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 创建一个包含搜索结果的列表
        /// </summary>
        /// <param name="content">搜索内容的英文版本</param>
        /// <param name="result">搜索内容的中文版本</param>
        /// <returns>包含一个ECResult对象的列表</returns>
        public List<PhraseResult> FindAllResult(string content, string result)
        {
            // 初始化一个包含单个ECResult对象的列表
            return new List<PhraseResult>(){
                new PhraseResult() {
                    Chinese= result,
                    Words= content,
                    Score= 0,
                    Distance= 0
                }
            };
        }

        #endregion

        #region 纠错

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 拼写纠正方法，用于修正输入的术语。
        /// </summary>
        /// <remarks>
        /// 多单术语成的术语纠错时与字典定义描述方法相同，使用'_'分割
        /// </remarks>
        /// <param name="Phrase">需要进行拼写纠正的术语。</param>
        /// <returns>返回纠正后的术语结果。</returns>
        public static PhraseResult SpellPhraseCorrect(string Phrase) {
            // 计算术语的拼写纠正建议
            var suggestions = SpellPhraseCorrectCal(Phrase);
            // 如果有建议，则处理第一个建议，否则返回原始术语及默认值
            return (suggestions.Count() > 0)
                ? SpellPhraseCorrectResult(suggestions.First())
                : SpellPhraseCorrectEmptyResult(Phrase);
        }

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 计算术语的拼写纠正建议的辅助方法。
        /// </summary>
        /// <param name="Phrase">需要计算的术语。</param>
        /// <returns>返回按相关性排序的建议列表。</returns>
        private static IOrderedEnumerable<SuggestItem> SpellPhraseCorrectCal(string Phrase) {
            // 返回按核心值降序排序的建议列表
            return EnglishSpell.SpellHandle.Lookup(Phrase, Verbosity.Closest, MaxLength).OrderByDescending(x => x.score).ThenByDescending(x => x.count);
        }

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 根据建议项生成拼写纠正结果。
        /// </summary>
        /// <param name="input">包含纠正建议的建议项。</param>
        /// <returns>返回包含纠正结果的 ECResult 对象。</returns>
        private static PhraseResult SpellPhraseCorrectResult(SuggestItem input) {
            var chinese = TreeSearch(input.term);
            // 使用建议项中的数据生成纠正结果
            return (chinese.Count == 0) 
                ? SpellPhraseCorrectEmptyResult(input.term)
                : SpellPhraseCorrectResult(chinese, input);
        }

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 拼写正确的词组结果
        /// </summary>
        /// <param name="chinese">建议对应的中文列表</param>
        /// <param name="input">包含纠正建议的建议项。</param>
        /// <returns></returns>
        private static PhraseResult SpellPhraseCorrectResult(List<PhraseResult> chinese, SuggestItem input) {
            // 使用建议项中的数据生成纠正结果
            return new PhraseResult() {
                Words = input.term,
                Chinese = chinese.Count > 0 ? chinese[0].Chinese : "",
                Distance = input.distance,
                Score = input.score,
            };
        }

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 生成拼写纠正空结果。
        /// </summary>
        /// <remarks>
        /// 多单术语成的特定术语返回时需将字典定义描述方法'_'分割更改为' '空格分割
        /// </remarks>
        /// <param name="input">输入的文本，当没有纠正建议时返回。</param>
        /// <returns>返回包含原始文本和默认值的 ECResult 对象。</returns>
        public static PhraseResult SpellPhraseCorrectEmptyResult(string input) {
            // 生成并返回没有纠正建议时的结果
            return new PhraseResult() {
                Words = input,
                Distance = 0,
                Score = 0,
            };
        }
        #endregion

        #region 枚举器
        ///////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 返回一个枚举器，用于遍历树中的键。
        /// </summary>
        /// <returns>返回一个字符串类型的枚举器。</returns>
        public IEnumerator<string> GetEnumerator()
        {
            // 使用Lambda表达式选择树中的所有键，然后返回枚举器
            return EClibrary.Keys.Select(x => x).GetEnumerator();
        }

        // /////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 支持枚举器接口，允许对象实现枚举功能。
        /// </summary>
        /// <returns>返回一个支持枚举的IEnumerator对象。</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            // 调用泛型版本的GetEnumerator方法以支持枚举
            return GetEnumerator();
        }
        #endregion
    }
}
